#pragma once
//网络应用里对消息进行路由分发，并且管理在线用户
#include<iostream>
#include<string>
#include<vector>
#include"InetAddr.hpp"
#include "Log.hpp"
#include "Mutex.hpp"

using namespace LogModule;
using namespace MutexModule;

//Route类的作用是维护在线用户列表，把消息从发送者路由到其他所有在线用户，
//同时处理用户退出的情况。它借助用户的网络地址（InetAddr类型）来识别不同用户
class Route
{
private:
    //判断某个用户是否在线，也就是检查传入的peer地址是否存在于_online_user向量中
    bool IsExist(InetAddr& peer)
    {
        for(auto& user : _online_user)
        {
            if(user == peer)
            {
                return true;
            }
        }
        return false;
    }

    void AddrUser(InetAddr& peer)
    {
        LOG(LogLevel::INFO) << "新增一个在线用户: " << peer.StringAddr();
        _online_user.push_back(peer);
    }

    void DeleteUser(InetAddr& peer)
    {
        //这里不能用范围for，因为其中的变量不是迭代器而是容器中的元素值或引用
        for(auto iter = _online_user.begin(); iter != _online_user.end(); iter++)
        {
            if(*iter == peer)
            {
                LOG(LogLevel::INFO) << "删除一个在线用户:" << peer.StringAddr() << "成功";
                _online_user.erase(iter);//erase需要传迭代器
                break;
            }
        }
    }

public:
    Route()
    {}
    
    void MessageRoute(int sockfd, const std::string& message, InetAddr& peer)
    {
        LockGuard lockguard(_mutex);

        //1. 新用户处理：要是发送消息的用户不在在线列表中，就调用AddUser函数把该用户添加进去
        if(!IsExist(peer))
        {
            AddrUser(peer);
        }
    
        //2. 消息格式处理：将消息格式进行转换，在原消息前面加上发送者的地址，例如"127.0.0.1:8080# 你好"
        std::string send_message = peer.StringAddr() + "# " + message;

        //3. 消息广播：通过sockfd套接字，把格式化后的消息发送给在线列表里的每一个用户
        for(auto& user : _online_user)
        {//将数据从指定套接字发送到目标地址,适用于发送未建立连接的 UDP 数据包/已连接的数据报或流式套接口发送数据
            sendto(sockfd, send_message.c_str(), send_message.size(), 0, 
            (const struct sockaddr*)&(user.NetAddr()), sizeof(user.NetAddr()));
        }

        //4. 用户退出处理：如果收到的消息内容是"QUIT"，就调用DeleteUser函数把发送者从在线列表中删除
        if(message == "QUIT")
        {
            LOG(LogLevel::INFO) << "删除一个在线用户: " << peer.StringAddr();
            DeleteUser(peer);
        }
    }

    ~Route()
    {
    }
    
private:
    // 首次给我发消息，等同于登录
    std::vector<InetAddr> _online_user;// 在线用户
    //拿多个客户端同时访问，是不安全的
    Mutex _mutex;
};